package battleships;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

import com.google.gson.Gson;

class Game {
	public Integer p1, p2;
	private String[] placements;
	private boolean[][][] occupied;
	private boolean[][][] bombed;
	private int[] hits;
	private boolean hasPlaced[];
	private Ship[][] ships;
	private Integer turn;
	private List<BlockingQueue<String>> message;
	
	Game(Integer p1, Integer p2) {
		this.p1 = p1;
		this.p2 = p2;
		turn = (int)(Math.random() * 2);
		
		placements = new String[2];
		message = new ArrayList<BlockingQueue<String>>();
		message.add(new ArrayBlockingQueue<String>(50));
		message.add(new ArrayBlockingQueue<String>(50));
		ships = new Ship[2][];
		hits = new int[2];
		ships[0] = new Ship[10];
		ships[1] = new Ship[10];
		
		hasPlaced = new boolean[2];
		occupied = new boolean[2][][];
		occupied[0] = new boolean[10][];
		occupied[1] = new boolean[10][];
		bombed = new boolean[2][][];
		bombed[0] = new boolean[10][];
		bombed[1] = new boolean[10][];
		for (int x = 0; x < 10; x++) {
			occupied[0][x] = new boolean[10];
			occupied[1][x] = new boolean[10];
			bombed[0][x] = new boolean[10];
			bombed[1][x] = new boolean[10];			
		}
	}
	
	public String getStatus(Integer player) {
		int p = player == p1 ? 0 : 1;
		HashMap<String, String> result = new HashMap<String, String>();
		if (hasPlaced[p]) {
			result.put("hasplaced", "1");
			result.put("started", hasPlaced[1-p] ? "1":"0");
			if (hasPlaced[1-p])
				result.put("turn", turn == p ? "1":"0");
			//Send the ship positions
			String r = "";
			for (Ship s : ships[p])
				r += s;
			result.put("myships", r);
			String mine = "";
			String opp = "";
			for (int x = 0; x < 10; x++)
				for (int y = 0; y < 10; y++) {
					mine += bombed[p][x][y] ? '1':'0';
					opp += bombed[1-p][x][y] ? '1':'0';
				}
			result.put("mineBombed", mine);
			result.put("oppBombed", opp);
		}
		else
			result.put("hasplaced", "0");
		Gson gson = new Gson();
		return gson.toJson(result);
	}
	
	private void addShip(int p, boolean horizontal, int length, int x, int y) {
		for (int i = 0; i < length; i++) {
			if (horizontal)
				occupied[p][x][y+i] = true;
			else
				occupied[p][x+i][y] = true;
		}
	}
	
	public String setPlacement(Integer player, String placement) {
		int p = player == p1 ? 0 : 1, l, x, y;
		hasPlaced[p] = true;
		placements[p] = placement;
		//place the ships
		for (int i = 0; i < 40; i += 4) {
			boolean hor = placement.charAt(i) == 'h';
			l = Character.digit(placement.charAt(i+1), 10);
			x = Character.digit(placement.charAt(i+2), 10);
			y = Character.digit(placement.charAt(i+3), 10);
			ships[p][i / 4] = new Ship(x, y, l, hor);
			addShip(p, hor, l, x, y);
		}
		//If other player starts, give him that message
		try {
			String a = Handler.getUserName(p1), b = Handler.getUserName(p2);
			if (p2 == p) {
				String t = a; a = b; b = t;
			}
			message.get(1-p).put((1-p) == turn ? ("start&"+a+"&"+b):("wait&"+a+"&"+b));
			return message.get(p).take();
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
	
	public String bomb(Integer player, int x, int y) {
		//returns "hit" or "miss"
		int p = player == p1 ? 0 : 1;
		System.err.println("=== Sending to " + (1-p) + ": " + x + " " + y);
		if (!bombed[1-p][x][y] && occupied[1-p][x][y]) {
			hits[p]++;
			bombed[1-p][x][y] = true;
			String msg = "hit";
			// check if we got the whole ship, return format
			// hit;hlxy" [h - horizontal(1,0), l - length, x,y - positions of start]
			for (Ship s : ships[1-p])
				if (s.containsCoordinate(x, y) && s.gotAll(bombed[1-p]))
					msg += ";"+s;
			// Game over
			if (hits[p] == 20) {
				msg += ";" + placements[1-p];
				message.get(1-p).add(x + "" + y + ";" + placements[p]);
			}
			else // just a normal hit
				message.get(1-p).add(x + "" + y);
			return msg;
		}
		else
			message.get(1-p).add(x + "" + y);
		turn = 1 - turn; //switch player
		return "miss";
	}
	
	public String getBomb(Integer player) {
		int p = player == p1 ? 0 : 1;
		System.err.println("=== Waiting " + p);
		try {
			String msg = message.get(p).take();
			System.err.println("=== Got Waiting for bomb" + p + " : " + msg);
			return msg;
		} catch (InterruptedException e) {
			throw new RuntimeException(e);
		}
	}
	
	public Integer winner() {
		if (hits[0] == 20) 
			return p1;
		if (hits[1] == 20) 
			return p2;
		return null;
	}
}
